home *** CD-ROM | disk | FTP | other *** search
- /*
- **
- ** $Id: ShowIFF.c,v 3.5 93/05/24 15:34:36 chris Exp $
- ** $Revision: 3.5 $
- **
- ** $Filename: ShowIFF/ShowIFF.c $
- ** $Author: Christian A. Weber $
- ** $Release: 23.2 $
- ** $Date: 93/05/24 15:34:36 $
- **
- ** NAME
- ** ShowIFF - a fast IFF picture viewer for Workbench and Shell
- **
- ** >>>> For full documentation, see ShowIFF.doc <<<<
- **
- ** DESCRIPTION
- ** ShowIFF can display any Amiga IFF pictures with up to 24 bitplanes
- ** (24 bit pictures are displayed in "true color" with max. colors).
- ** All known formats (HAM, HAM8, Halfbrite) and all display modes
- ** like NTSC, PAL, VGA, A2024, ... are supported.
- ** If a picture is larger than the screen, you can use the mouse to
- ** scroll around.
- ** ShowIFF can be used from Workbench or Shell, it can create an
- ** AppIcon. It can display single files or whole drawers or disks.
- **
- ** REQUIREMENTS
- ** - iff.library V22+
- ** - Amiga OS 2.0 or newer (3.0 for AGA modes)
- ** - Original, Enhanced or AGA chipset
- ** - to compile: SAS/C compiler V6
- **
- ** AUTHOR
- ** Christian A. Weber
- **
- ** Internet: weber@amiga.physik.unizh.ch
- ** UUCP: chris@mighty.adsp.sub.org
- ** Snail mail: Bruggerweg 2, CH-8037 Zürich, Switzerland.
- **
- ** Suggestions, bug reports or donations are welcome.
- **
- ** LEGAL STUFF
- ** COPYRIGHT (C) 1987-1993 BY CHRISTIAN A. WEBER. ALL RIGHTS RESERVED.
- ** THIS PROGRAM MAY BE DISTRIBUTED FOR NON PROFIT PURPOSES ONLY.
- ** NO WARRANTY. USE AT YOUR OWN RISK.
- **
- ** HISTORY
- **
- ** 15-Oct-87 CHW V1.0 Created this file!
- ** 30-Jun-88 CHW V1.4 Directory scan fixed for FFS, cleaned up
- ** 16-Nov-88 CHW V1.5 Overscan implemented
- ** 28-Nov-88 CHW V1.6 Minimal screen size is now 64x64 pixels
- ** 02-Jan-89 CHW V1.7 Double-buffering implemented
- ** 25-Sep-89 CHW V2.01 Changed to Lattice C and ARP library
- ** 27-Sep-89 CHW V2.02 Screen scrolling implemented
- ** 22-Nov-89 CHW V2.03 Rejects Non-ILBM files correctly
- ** 21-Feb-90 CHW V2.04 'NoMemForGfx' bug fixed, overscan fixed
- ** 28-Feb-90 CHW V2.10 SHAM support code added
- ** 14-Mar-90 CHW V2.11 Memory fragmentation workaround, cleanup
- ** 08-Apr-90 CHW V2.12 Pics with more than 6 planes don't guru
- ** 22-Apr-90 CHW V2.14 New startup code, WB cleanup works now.
- ** 16-Jul-90 CHW V2.15 Works now properly with MoreRows & OS 2.0
- ** 16-Sep-90 CHW V2.16 Scrolling SHAM pictures implemented
- ** 03-Oct-90 CHW V2.17 MaxX0 divided by 2 because of a 2.0 bug
- ** 30-Oct-90 MAB V2.20 ShowIFF can be turned into an appicon
- ** 11-Jan-91 CHW V2.21 SHAM color errors fixed
- ** 11-Jan-91 CHW V2.22 AppIcon image/pos are taken from .info file
- ** 13-Jan-91 CHW V2.23 COMMAND mode added, overscan bug fixed (?)
- ** 14-Jan-91 CHW V2.24 Icon tooltypes added, code moved around
- ** 24-Jan-91 CHW V2.25 Minor bug fixes
- ** 03-May-91 CHW V2.26 Vertical centering and NOCENTER option added
- ** 23-May-91 CHW V2.27 Pointer option added
- ** 27-May-91 CHW V2.28 True Color Table fixed and extended
- ** 23-Jun-91 CHW V2.29 AppIcon's image can be specified (ICON=...)
- ** 23-Apr-92 CHW V2.30 RasInfo-bug workaround only under V36-38
- ** 29-Jul-92 CHW V2.31 Compiles with new IFF includes, 8 bitplanes
- ** 15-Oct-92 SG V3.00 New display code, true AGA support
- ** 01-Dec-92 CHW V3.1 ARP support removed, substancial rewrite
- ** 04-Feb-92 CHW V3.4 Bug in ScrollRaster() call removed (would crop)
- */
-
- // #define VERBOSE
-
- #include <hardware/custom.h> /* For SHAM/DYNA support ONLY */
- #include <proto/exec.h>
- #include <exec/memory.h>
- #include <exec/execbase.h>
- #include <proto/utility.h>
- #include <utility/utility.h>
- #include <proto/graphics.h>
- #include <graphics/gfxbase.h>
- #include <graphics/gfxmacros.h>
- #include <graphics/displayinfo.h>
- #include <proto/intuition.h>
- #include <intuition/intuitionbase.h>
- #include <proto/icon.h>
- #include <workbench/icon.h>
- #include <proto/wb.h>
- #include <workbench/startup.h>
- #include <proto/dos.h>
-
- #include <string.h>
- #include <stdlib.h>
-
- #include <libraries/iff.h>
-
- #include "showiff_rev.h"
-
-
- /****************************************************************************
- ** Some useful macros
- */
-
- #define MAX(a,b) ((a)>(b)?(a):(b))
- #define OSVERSION(ver) (IntuitionBase->LibNode.lib_Version >= (ver))
- #define HAS_AGA (GfxBase->ChipRevBits0 & GFXF_AA_ALICE)
-
- #define PICF_DYNA 1
-
- #define MAXCOLORS 256
-
- #define XOSCAN 0 /* Scroll if picture is bigger than screen + XOSCAN */
- #define YOSCAN 16 /* Scroll if picture is bigger than screen + YOSCAN */
-
-
- /****************************************************************************
- ** Stuctures
- */
-
- typedef struct
- {
- UBYTE R, G, B; /* Red, Green, Blue values (0..255) */
- } RGBColor;
-
-
- struct Picture
- {
- struct Screen *Screen; /* The picture's screen */
- struct Window *Window; /* Window for mouse handling */
- struct BitMap *BitMap; /* BitMap, can be larger than screen */
- UWORD *SHAMColors; /* SHAM color table array or NULL */
- WORD Y0; /* Y of picture relative to screen */
- UWORD PicW, PicH; /* Total image dimensions */
- UWORD ColorCount; /* # of colors in color palette */
- RGBColor Palette[MAXCOLORS]; /* The picture's color palette */
- UBYTE Flags; /* See PICF_... */
- };
-
- struct SHAMChunk
- {
- struct IFFL_Chunk Chunk;
- UWORD Version;
- UWORD Colors[1]; /* open array */
- };
-
-
- /****************************************************************************
- ** Tooltypes and other constant strings
- */
-
- #define OPTIONSTOOLTYPE "OPTIONS"
- #define ICONTOOLTYPE "ICON"
- #define XPOSTOOLTYPE "ICONXPOS"
- #define YPOSTOOLTYPE "ICONYPOS"
- #define ICONNAMETOOLTYPE "ICONNAME"
- #define APPICONPORTNAME "ShowIFF-AppIcon"
- #define DEFAULTAPPICONNAME "IFF Picture Viewer"
-
-
- /****************************************************************************
- ** External references
- */
-
- extern struct Process *ProcessBase; /* Pointer to our process */
- extern struct Custom __far custom; /* For SHAM/DYNA copper list */
-
-
- /****************************************************************************
- ** Global variables
- */
-
- struct Library *UtilityBase, *IconBase, *WorkbenchBase;
- struct GfxBase *GfxBase;
- struct IntuitionBase *IntuitionBase;
- struct Library *IFFBase; /* Nothing goes without that */
-
- struct DiskObject *dobj; /* Our icon */
- IFFL_HANDLE ifffile; /* IFF file handle */
- struct Picture pic1, pic2; /* 2 pictures for double buffering */
- BPTR wbwindow; /* Output window for Workbench mode */
- BPTR oldcos; /* Old output file handle */
- LONG delay = 0x7fffffff; /* Time (in jiffies) for each picture */
- LONG monitorid; /* Monitor ID or 0 if no specific monitor */
-
- WORD __chip emptysprite[8]; /* ShowIFF's mouse pointer sprite */
-
-
- static char VersionString[] =
- VERSTAG " by Christian A. Weber and Peter W. Simeon\n\r";
-
- static char WindowTitle[] =
- "CON:10/24/600/92/" VERS " (" DATE ")/AUTO/CLOSE";
-
- char StdWindowName[] = "NIL:"; /* Default Workbench window name */
-
-
- /*
- ** CLI_Template and argv are used for ArgsStartup20.o. Argv receives the
- ** arguments from a ReadArgs() call in the startup code. CLI_Help will
- ** be printed if no arguments are specified on the command line.
- */
-
- char CLI_Template[] =
- "Patterns/M,ALL/S,D=DELAY/N,L=LOOP/S,MONITOR/K,NB=NOBREAK/S,NOCENTER/S,"
- "NO=NOOVERSCAN/S,POINTER/S,CMD=COMMAND/K";
-
- static char CLI_Help[] =
- "Usage: ShowIFF [files or patterns] [ALL] [DELAY delay] [LOOP] [MONITOR id]\n"
- "\t[NOBREAK] [NOCENTER] [NOOVERSCAN] [POINTER] [COMMAND \"Command %s args\"]\n";
-
- struct
- {
- char **Patterns;
- LONG AllFlag;
- LONG *DelayPtr;
- LONG LoopFlag;
- char *Monitor;
- LONG NoBreakFlag;
- LONG NoCenterFlag;
- LONG NoOverscanFlag;
- LONG PointerFlag;
- char *Command;
- } argv;
-
-
- /****************************************************************************
- ** Make sure a value is between two borders
- */
-
- LONG SetBounds(LONG is, LONG min, LONG max)
- {
- if (is > max) is = max;
- if (is < min) is = min;
- return is;
- }
-
-
- /****************************************************************************
- ** Get a positive number in hex ($1234 or 0x1234) or decimal
- */
-
- static ULONG GetNumber(char *string)
- {
- ULONG Atoi(char *), Atox(char *);
-
- if ((string[0] == '0') && (string[1] == 'x'))
- {
- string++;
- goto hex;
- }
- else if (string[0] == '$')
- {
- hex:
- string++;
- return Atox(string);
- }
- else return Atoi(string);
- }
-
-
- /***************************************************************************
- ** Get the secondary error from iff.library and display an error text
- */
-
- static void PrintIFFError(void)
- {
- char *text;
-
- switch (IFFL_IFFError() )
- {
- case IFFL_ERROR_OPEN:
- text = "Can't open file";
- break;
-
- case IFFL_ERROR_READ:
- text = "Error reading file";
- break;
-
- case IFFL_ERROR_NOMEM:
- text = "Not enough memory";
- break;
-
- case IFFL_ERROR_NOTIFF:
- text = "Not an IFF file";
- break;
-
- case IFFL_ERROR_NOBMHD:
- text = "No IFF BMHD found";
- break;
-
- case IFFL_ERROR_NOBODY:
- text = "No IFF BODY found";
- break;
-
- case IFFL_ERROR_BADCOMPRESSION:
- text = "Unsupported compression mode";
- break;
-
- default:
- text = "Unspecified error";
- break;
- }
-
- Printf("%s\n", text);
- }
-
-
- /***************************************************************************
- ** V37 replacement for FreeBitMap()
- */
-
- void MyFreeBitMap(struct BitMap *bm)
- {
- if (OSVERSION(39) )
- {
- FreeBitMap(bm);
- }
- else /* Running under V37 */
- {
- LONG planesize = bm->BytesPerRow * bm->Rows;
- int i;
-
- for (i = 0; i < bm->Depth; ++i)
- {
- if (bm->Planes[i])
- {
- FreeMem(bm->Planes[i], planesize);
- }
- }
- FreeVec(bm);
- }
- }
-
-
- /***************************************************************************
- ** Allocate a BitMap structure and allocate CHIP memory for the planes.
- */
-
- struct BitMap *MyAllocBitMap(LONG depth, LONG width, LONG height)
- {
- struct BitMap *bm;
-
- if (OSVERSION(39) )
- {
- bm = AllocBitMap(width, height, depth, BMF_CLEAR | BMF_DISPLAYABLE, NULL);
- }
- else
- {
- LONG planesize, bmsize = sizeof(struct BitMap);
-
- /*
- ** If the bitmap has more than 8 planes, we add the size of the
- ** additional plane pointers to the amount of memory we allocate
- ** for the bitmap structure.
- */
- if (depth > 8)
- bmsize += sizeof(PLANEPTR) * (depth-8);
-
- if (bm = AllocVec(bmsize, MEMF_PUBLIC | MEMF_CLEAR) )
- {
- int i;
-
- InitBitMap(bm, depth, width, height);
- planesize = bm->BytesPerRow * bm->Rows;
-
- for (i = 0; i < depth; ++i)
- {
- if (bm->Planes[i] = AllocMem(planesize, MEMF_CHIP | MEMF_CLEAR) )
- {
- }
- else
- {
- MyFreeBitMap(bm);
- bm = NULL;
- break;
- }
- }
- }
- }
-
- return bm;
- }
-
-
- /****************************************************************************
- ** Load a color palette (24 bit resolution)
- */
-
- static void LoadRGB8(struct ViewPort *vp, RGBColor *color, int count)
- {
- int i;
-
- for (i=0; i < count; ++color, ++i)
- {
- if (OSVERSION(39) )
- {
- SetRGB32(vp, i, color->R<<24, color->G<<24, color->B<<24);
- }
- else
- {
- SetRGB4(vp, i, color->R>>4, color->G>>4, color->B>>4);
- }
- }
- }
-
-
- /****************************************************************************
- ** Create a truecolor 24bit palette with <1 << totalbits> entries.
- ** The bitplanes will have the order G6G7R7B7 or G4G5G6G7R6R7B6B7 ...
- ** Plane#: 0 1 2 3 0 1 2 3 4 5 6 7
- ** The result is the number of green planes (red and blue have always the
- ** same number and can be calculated as (totalbits-greenbits)/2).
- */
-
- static int CreateTrueColorPalette(RGBColor *palette, int totalbits)
- {
- int numcolors, i, rbits, gbits, bbits, rlevels, glevels, blevels;
-
- numcolors = 1 << totalbits;
-
- /*
- ** Divide the total number of bits into the bits for r/g/b. Green is
- ** the most important color, so it gets the remaining bits as well.
- */
- rbits = gbits = bbits = totalbits / 3;
- gbits += totalbits % 3;
-
- rlevels = 1 << rbits;
- glevels = 1 << gbits;
- blevels = 1 << bbits;
-
- for (i=0; i<numcolors; ++palette, ++i)
- {
- palette->G = (( i % glevels) * 0xFF) / (glevels-1);
- palette->R = (((i >> gbits) % rlevels) * 0xFF) / (rlevels-1);
- palette->B = (((i >> (gbits+rbits)) % blevels) * 0xFF) / (blevels-1);
- }
-
- return gbits;
- }
-
-
- /****************************************************************************
- ** Create intermediate SHAM copper list if this is an SHAM picture.
- ** This feature will probably be removed; with AGA it's useless anyway.
- */
-
- void MakeSHAMCopList(struct Picture *pic)
- {
- struct UCopList *ucop;
-
- if (!pic->SHAMColors) return; /* Not an SHAM picture, no work to do */
-
- if (ucop = AllocMem(sizeof(*ucop), MEMF_PUBLIC | MEMF_CLEAR) )
- {
- struct Screen *s = pic->Screen;
- LONG i, j, step = (s->ViewPort.Modes&LACE) ? 2:1;
- UWORD copx = GfxBase->ActiView->DxOffset + s->Width;
- UWORD y0 = s->ViewPort.RasInfo->RyOffset;
-
- if (pic->Flags & PICF_DYNA) step = 1;
-
- for (i=1; i < (s->Height/step); ++i)
- {
- CWAIT(ucop, pic->Y0 + (i-1)*step, (UWORD)((copx>>1) % (UWORD)228))
- for(j=1; j<16; ++j)
- CMOVE(ucop, custom.color[j], pic->SHAMColors[16*(y0+i)+j])
- }
- CEND(ucop)
- // FreeVPortCopLists(&s->ViewPort);
- s->ViewPort.UCopIns = ucop;
- // pic->SHAMColors[16*y0] = pic->ColorTab[0]; /* Fix some weird SHAM pics */
- LoadRGB4(&s->ViewPort, &pic->SHAMColors[16*y0], 16);
- }
- }
-
-
- /****************************************************************************
- ** Free a picture (that is a window, screen and a custom BitMap)
- */
-
- void ClosePicture(struct Picture *pic)
- {
- if (pic->Window)
- {
- ScreenToBack(pic->Screen);
- ClearPointer(pic->Window);
- CloseWindow(pic->Window);
- pic->Window = NULL;
- }
-
- if (pic->Screen)
- {
- CloseScreen(pic->Screen);
- pic->Screen = NULL;
- }
-
- if (pic->BitMap)
- {
- MyFreeBitMap(pic->BitMap);
- pic->BitMap = NULL;
- }
-
- RemakeDisplay(); /* remake copper list to increase MEMF_LARGEST */
- }
-
-
- /****************************************************************************
- ** Get the view mode for a picture. If there is a CAMG chunk, we just
- ** return its contents. If there is none, we ask the graphics library for
- ** help. If it can't help us (<3.0), we calculate a view mode by hand.
- */
-
- static ULONG GetBestViewMode(IFFL_HANDLE iff, struct IFFL_BMHD *bmhd)
- {
- ULONG viewmode;
-
- /*
- ** We don't want iff.library to give us a default viewmode if no
- ** CAMG is present, so we must check first for a CAMG, and only
- ** if it's there we can call IFFL_GetViewModes()
- */
- if (IFFL_FindChunk(iff, ID_CAMG) )
- {
- viewmode = IFFL_GetViewModes(iff);
- #ifdef VERBOSE
- Printf("CAMG: $%08lx ", viewmode);
- #endif
- }
- else
- {
- viewmode = INVALID_ID;
-
- if (OSVERSION(39) )
- {
- viewmode = BestModeID(
- BIDTAG_NominalWidth, bmhd->w,
- BIDTAG_NominalHeight, bmhd->h,
- BIDTAG_DesiredWidth, bmhd->w,
- BIDTAG_DesiredHeight, bmhd->h,
- BIDTAG_Depth, bmhd->nPlanes,
-
- // BIDTAG_MonitorID, monitorid,
-
- monitorid ? BIDTAG_MonitorID : TAG_IGNORE,
- monitorid,
- TAG_DONE
- );
- #ifdef VERBOSE
- Printf("BESTID: $%08lx ", viewmode);
- #endif
- }
- }
-
- /*
- ** If we don't have a valid viewmode by now, let's handcraft it...
- */
- if (viewmode == INVALID_ID)
- {
- #if 0
- /*
- ** $$$ This is for non-aga only!!! fix!!
- */
- viewmode = 0;
- if((bmhd->nPlanes <=4) || (bmhd->nPlanes == 24))
- {
- if(bmhd->w > 400) viewmode |= HIRES_KEY;
- }
- else if(bmhd->nPlanes == 6) viewmode |= HAM_KEY;
-
- if(bmhd->h > 320) viewmode |= LORESLACE_KEY;
- #else
- viewmode = monitorid; // Test
- #endif
-
- #ifdef VERBOSE
- Printf("MY GUESS: $%08lx ", viewmode);
- #endif
- }
-
- return viewmode;
- }
-
-
- /****************************************************************************
- ** Allocate a picture (Allocate custom BitMap, open screen and window)
- */
-
- BOOL OpenPicture(struct Picture *pic)
- {
- struct DimensionInfo di;
- struct IFFL_BMHD *bmhd;
- ULONG viewmode, overscan;
- int xpos, ypos, width, height, depth;
-
- /*
- ** If this picture was already loaded, free it.
- */
- ClosePicture(pic);
- memset(pic, 0, sizeof(*pic));
-
-
- /*
- ** First, we get the BMHD chunk from the file. If there is none,
- ** we show an error message and return.
- */
- if ( !(bmhd = IFFL_GetBMHD(ifffile)) )
- {
- PrintIFFError();
- return FALSE;
- }
-
- Printf("%ld x %ld x %ld ", bmhd->w, bmhd->h, bmhd->nPlanes);
- Flush(Output());
-
-
- /*
- ** Get the viewmodes and its monitor dimension info, and calculate
- ** the screen position, width and height. If the picture is larger
- ** than the max overscan area, it is displayed with OSCAN_TEXT, and
- ** can be scrolled with the mouse.
- */
- viewmode = GetBestViewMode(ifffile, bmhd);
-
- if (GetDisplayInfoData(NULL,(UBYTE *)&di, sizeof(di), DTAG_DIMS, viewmode) )
- {
- BOOL scroll = FALSE;
-
- int maxwidth = di.VideoOScan.MaxX - di.VideoOScan.MinX + 1;
- int maxheight = di.VideoOScan.MaxY - di.VideoOScan.MinY + 1;
-
- int stdwidth = di.TxtOScan.MaxX - di.TxtOScan.MinX + 1;
- int stdheight = di.TxtOScan.MaxY - di.TxtOScan.MinY + 1;
-
- width = SetBounds(bmhd->w, di.MinRasterWidth, maxwidth+XOSCAN);
- height = SetBounds(bmhd->h, stdheight, maxheight+YOSCAN);
- depth = SetBounds(bmhd->nPlanes, 1, di.MaxDepth);
-
- if (bmhd->w > (maxwidth+XOSCAN)) /* Too wide, scroll horizontally */
- {
- width = stdwidth;
- scroll = TRUE;
- }
-
- if (bmhd->h > (maxheight+YOSCAN)) /* Too high, scroll vertically */
- {
- height = stdheight;
- scroll = TRUE;
- }
-
- if (((bmhd->w > stdwidth) || (bmhd->h > stdheight)) && !scroll)
- {
- overscan = OSCAN_VIDEO;
- }
- else overscan = OSCAN_TEXT;
-
- pic->PicW = bmhd->w;
- pic->PicH = bmhd->h;
- pic->Y0 = SetBounds((height - bmhd->h) / 2, 0, height);
-
- if (!argv.NoCenterFlag)
- {
- xpos = (stdwidth - width) / 2;
- ypos = (stdheight - height) / 2;
- }
- else
- {
- xpos = ypos = pic->Y0 = 0;
- }
-
- #ifdef VERBOSE
- Printf("\nScr(%ld x %ld x %ld) Max(%ld x %ld x %ld) ",
- width, height, depth, maxwidth, maxheight, di.MaxDepth);
- #endif
- }
- else
- {
- switch (ModeNotAvailable(viewmode) )
- {
- case DI_AVAIL_NOCHIPS:
- Printf("You need a better chipset for view mode $%08lx\n", viewmode);
- break;
-
- case DI_AVAIL_NOMONITOR:
- Printf("The required monitor ($%08lx) is not available\n", viewmode);
- break;
-
- case DI_AVAIL_NOTWITHGENLOCK:
- Printf("The monitor $%08lx does not support genlocks\n", viewmode);
- break;
-
- default:
- Printf("View mode $%08lx not available.\n", viewmode);
- break;
- }
-
- return FALSE;
- }
-
-
- /*
- ** Allocate the screen's bitmap
- */
- if (pic->BitMap = MyAllocBitMap(
- bmhd->nPlanes, MAX(bmhd->w, width), MAX(bmhd->h, height)) )
- {
- ULONG oserror;
-
- pic->BitMap->Depth = depth; /* Make OpenScreen() work */
-
- /*
- ** Now open the screen
- */
- if (pic->Screen = OpenScreenTags(NULL,
- SA_Left, xpos,
- SA_Top, ypos,
- SA_Width, width,
- SA_Height, height,
- SA_Depth, depth,
- SA_BitMap, pic->BitMap,
- SA_Behind, TRUE,
- SA_Quiet, TRUE,
- SA_Type, CUSTOMSCREEN,
- SA_DisplayID, viewmode,
- SA_Overscan, overscan,
- SA_ErrorCode, &oserror,
- TAG_DONE
- ))
- {
- UBYTE *colortab;
-
- pic->BitMap->Depth = bmhd->nPlanes; /* Undo cheat */
-
- /*
- ** Create the color palette (read from CMAP chunk, if any)
- */
- if (bmhd->nPlanes == 24)
- {
- /*
- ** If we have a 24bit true color picture, we calculate a
- ** "true color" palette and use the screen's most significant
- ** bitplanes for our reduced true color picture. This doesn't
- ** look perfect, but is FAST. Feel free to enhance this.
- */
- int greenbits, rbbits, i;
-
- // depth = 3;
-
- greenbits = CreateTrueColorPalette(pic->Palette, depth);
- rbbits = (depth-greenbits)/2;
-
- /*
- ** Rearrange the bitplane pointers of our screen.
- ** This is not quite legal, I suppose (but OK for PD :-))
- */
- for (i=0; i<greenbits; ++i)
- {
- pic->Screen->BitMap.Planes[i] =
- pic->BitMap->Planes[16-greenbits+i];
- }
-
- for (i=0; i < rbbits; ++i)
- {
- pic->Screen->BitMap.Planes[greenbits+i] =
- pic->BitMap->Planes[8-rbbits+i];
-
- pic->Screen->BitMap.Planes[greenbits+rbbits+i] =
- pic->BitMap->Planes[24-rbbits+i];
- }
-
- pic->ColorCount = 1 << depth;
- }
- else if (colortab = IFFL_FindChunk(ifffile, ID_CMAP) )
- {
- pic->ColorCount =
- SetBounds(*(ULONG *)(colortab+4) / 3, 0, MAXCOLORS);
-
- CopyMem(colortab+8, pic->Palette,
- pic->ColorCount * sizeof(RGBColor));
- }
- else
- {
- /*
- ** Use default colors for pictures without a CMAP
- */
- static RGBColor white = { 0xEE, 0xCC, 0xAA };
- pic->ColorCount = 2;
- pic->Palette[0] = white;
- // pic->Palette[1] = black;
- }
-
- LoadRGB8(&pic->Screen->ViewPort, pic->Palette, pic->ColorCount);
-
-
- /*
- ** To get our intuimessages, we open a window in the screen
- */
- if (pic->Window = OpenWindowTags(NULL,
- WA_Flags, WFLG_BACKDROP | WFLG_BORDERLESS
- | WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH
- | WFLG_NOCAREREFRESH | WFLG_REPORTMOUSE
- | WFLG_RMBTRAP,
- WA_IDCMP, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE
- | IDCMP_DELTAMOVE | IDCMP_VANILLAKEY,
- WA_CustomScreen, pic->Screen,
- TAG_DONE
- ))
- {
- /*
- ** Clear the mouse pointer if desired
- */
- if( !argv.PointerFlag)
- SetPointer(pic->Window, emptysprite, 1L, 16L, 0L, 0L);
-
- return TRUE;
- }
- }
- else switch (oserror) /* OpenScreenTags() failed */
- {
- case OSERR_NOMONITOR:
- PutStr("Monitor not available.\n");
- break;
-
- case OSERR_NOCHIPS:
- PutStr("You need newer custom chips.\n");
- break;
-
- case OSERR_NOMEM:
- PutStr("Not enough free main memory.\n");
- break;
-
- case OSERR_NOCHIPMEM:
- PutStr("Not enough free chip mempry.\n");
- break;
-
- case OSERR_UNKNOWNMODE:
- PutStr("Bad screen mode.\n");
- break;
-
- case OSERR_TOODEEP:
- PutStr("Too many colors requested.\n");
- break;
-
- case OSERR_NOTAVAILABLE:
- PutStr("Can't open screen.\n");
- break;
-
- default:
- PutStr("You're completely lost.\n");
- break;
- }
- }
- else PutStr("Not enough memory\n");
-
- ClosePicture(pic);
- return FALSE;
- }
-
-
- /****************************************************************************
- ** That's the big one! Load and display a picture, handle mouse movement
- ** and other input events.
- ** Returns FALSE if user presses the RMB (abort), else returns TRUE
- */
-
- BOOL ShowPicture(char *name)
- {
- BOOL cont = TRUE;
-
- /*
- ** Skip icon files
- */
- {
- int len = strlen(name);
- if (len >= 5)
- {
- if ( !Stricmp(name + len-5, ".info") )
- return TRUE;
- }
- }
-
- Printf("%s ... ", name);
- Flush(Output());
-
-
- /*
- ** Load the IFF file into memory. If a file was already loaded, free
- ** its memory first.
- */
- if(ifffile) IFFL_CloseIFF(ifffile);
-
- if ( !(ifffile = IFFL_OpenIFF(name, IFFL_MODE_READ)) )
- {
- PrintIFFError();
- return TRUE;
- }
-
- if ( *(((ULONG *)ifffile)+2) != ID_ILBM)
- {
- PutStr("Not an ILBM picture\n");
- return TRUE;
- }
-
- retry:
- if (OpenPicture(&pic1) )
- {
- if (IFFL_DecodePic(ifffile, pic1.BitMap) )
- {
- struct SHAMChunk *sham;
- LONG i;
- int xoff = 0, yoff = 0;
- int maxx0 = pic1.PicW - pic1.Screen->Width;
- int maxy0 = pic1.PicH - pic1.Screen->Height;
-
- /*
- ** In 2.0 there's this RasInfo scrolling bug, it's fixed
- ** for 3.0, so we'll make an explicit version check, and
- ** a workaround for the bug.
- */
- if (pic1.Screen->ViewPort.Modes & HIRES)
- {
- if( (GfxBase->LibNode.lib_Version >= 36)
- && (GfxBase->LibNode.lib_Version <= 38) )
- maxx0 >>= 1;
- }
-
-
- /*
- ** If the picture is not as high as the screen, we have to
- ** move it down so it will be centered.
- */
- if (pic1.Y0)
- {
- // Printf("ScrollRaster(rp,0,%ld,0,0,%ld,%ld)\n",-pic1.Y0,pic1.PicW-1,pic1.PicH-1);
- ScrollRaster(&pic1.Screen->RastPort,
- 0, -pic1.Y0, 0, 0, pic1.PicW-1, pic1.PicH+pic1.Y0-1);
- }
-
-
- /*
- ** If an SHAM or DYNA chunk is found, build the appropriate
- ** copper list to display the picture. This may not be supported
- ** in future versions.
- */
- if (sham = IFFL_FindChunk(ifffile, ID_SHAM) )
- {
- Printf("SHAM ");
- if (sham->Version == 0)
- {
- pic1.SHAMColors = sham->Colors;
- }
- else Printf("Unsupported mode: %ld ", (LONG)sham->Version);
-
- MakeSHAMCopList(&pic1);
- }
-
- if (sham = IFFL_FindChunk(ifffile, ID_CTBL) )
- {
- Printf("DYNA ");
- pic1.SHAMColors = &sham->Version; /* DYNA has no version */
- pic1.Flags |= PICF_DYNA;
- MakeSHAMCopList(&pic1);
- }
-
- Flush(Output());
-
-
- /*
- ** Display the picture, and close a possible old one
- */
- ScreenToFront(pic1.Screen);
- ClosePicture(&pic2);
-
-
- /*
- ** And now for the event loop ...
- */
- for (i = 0; i < delay; ++i)
- {
- struct IntuiMessage *msg;
-
- WaitTOF();
- while (msg = (struct IntuiMessage *)GetMsg(pic1.Window->UserPort) )
- {
- newmsg: switch(msg->Class)
- {
- case IDCMP_MOUSEMOVE:
-
- xoff += msg->MouseX;
- yoff += msg->MouseY;
- xoff = SetBounds(xoff, 0, maxx0);
- yoff = SetBounds(yoff, 0, maxy0);
-
- pic1.Screen->ViewPort.RasInfo->RxOffset = xoff;
- pic1.Screen->ViewPort.RasInfo->RyOffset = yoff;
-
- /*
- ** If there is an SHAM copper list, we must
- ** update it if the user scrolled the picture.
- ** This is quite slow, so we collect all mouse
- ** movement messages during this time.
- */
- if (pic1.SHAMColors)
- {
- struct IntuiMessage *m2;
-
- MakeSHAMCopList(&pic1);
- while (m2 = (struct IntuiMessage *)GetMsg(pic1.Window->UserPort) )
- {
- ReplyMsg(msg); msg = m2;
-
- if(msg->Class == IDCMP_MOUSEMOVE)
- {
- xoff += msg->MouseX;
- yoff += msg->MouseY;
- }
- else goto newmsg;
- }
- }
-
- /*
- ** Now make the changes visible. Under V39 we
- ** use the updated ScrollVPort() routine.
- */
- #if 0
- if (OSVERSION(39) )
- {
- ScrollVPort(&pic1.Screen->ViewPort);
- }
- else
- #endif
- {
- MakeScreen(pic1.Screen);
- RethinkDisplay();
- }
- break;
-
- case IDCMP_VANILLAKEY:
- if (msg->Code == 'c')
- {
- if (argv.Command)
- {
- char buf[200];
- sprintf(buf, argv.Command, name, name);
- Execute(buf, NULL, Output());
- }
- }
- break;
-
- case IDCMP_MOUSEBUTTONS:
- if (!argv.NoBreakFlag)
- {
- if (msg->Code == MENUDOWN) goto usrbreak;
- if (msg->Code == SELECTDOWN) goto showend;
- }
- break;
- }
-
- ReplyMsg(msg);
- }
-
- /*
- ** If the user hits Ctrl-C we quit, if not NOBREAK
- */
- if (!argv.NoBreakFlag)
- {
- if (CheckSignal(SIGBREAKF_CTRL_C) )
- {
- usrbreak: PutStr("***BREAK\n");
- cont = FALSE;
- goto showend2;
- }
- }
- }
-
- showend:
- PutStr("- Done\n");
-
- showend2:
- pic2 = pic1;
- memset(&pic1, 0, sizeof(pic1) );
- }
- else
- {
- ClosePicture(&pic1);
- PrintIFFError();
- }
- }
- else if(pic2.Window)
- {
- ClosePicture(&pic2);
- goto retry;
- }
-
- return cont;
- }
-
-
- /****************************************************************************
- ** Expand a pattern and call ShowPicture() for each matching file.
- ** Rreturn FALSE if the user presses ^C, or if ShowPicture() returned FALSE.
- */
-
- BOOL ShowPattern(char *pathname)
- {
- char buf[256];
- BPTR file;
- BOOL cont = TRUE;
-
- /*
- ** Check if the supplied pathname contains any wildcards. In this
- ** case (ParsePattern() returns TRUE) we scan the directory.
- ** If no wildcards are found, we just pass along the name to
- ** ShowPicture(), if it is not the name of a directory.
- */
- if (ParsePatternNoCase(pathname, buf, sizeof(buf)) )
- {
- struct
- {
- struct AnchorPath APath;
- char FullPath[255]; /* cheap way to extend ap_Buf[] */
- } *myanchor;
-
- iswild:
- if (myanchor = AllocVec(sizeof(*myanchor), MEMF_PUBLIC | MEMF_CLEAR) )
- {
- BOOL showit = TRUE;
- LONG error;
-
- myanchor->APath.ap_Strlen = sizeof(myanchor->FullPath);
- myanchor->APath.ap_Flags = APF_DOWILD;
- myanchor->APath.ap_BreakBits = SIGBREAKF_CTRL_C;
-
- error = MatchFirst(pathname, myanchor);
-
- while (!error)
- {
- if (CheckSignal(SIGBREAKF_CTRL_E) )
- {
- PutStr("***DIR BREAK\n"); showit=FALSE;
- /* myanchor->APath.ap_Flags &= ~APF_DODIR; */
- }
-
- if(myanchor->APath.ap_Info.fib_DirEntryType >= 0) /* Dir */
- {
- if (argv.AllFlag)
- {
- if ( !(myanchor->APath.ap_Flags & APF_DIDDIR) )
- {
- myanchor->APath.ap_Flags |= APF_DODIR;
- showit = TRUE;
- }
- myanchor->APath.ap_Flags &= ~APF_DIDDIR;
- }
- }
- else if(showit)
- {
- if (!ShowPicture(myanchor->APath.ap_Buf) )
- {
- cont = FALSE;
- break;
- }
- }
- error = MatchNext(myanchor);
- }
-
- MatchEnd(myanchor);
-
-
- /*
- ** Find out why the loop terminated
- */
- switch(error)
- {
- case 0:
- break;
-
- case ERROR_BREAK:
- PutStr("***BREAK\n");
- cont = FALSE;
- break;
-
- case ERROR_OBJECT_NOT_FOUND:
- PutStr("File not found\n");
- cont = FALSE;
- break;
-
- case ERROR_BUFFER_OVERFLOW:
- PutStr("Path too long\n");
- break;
-
- case ERROR_NO_MORE_ENTRIES: /* Normal termination */
- break;
-
- default:
- PrintFault(error, "");
- break;
- }
-
- FreeVec(myanchor);
- }
- else PutStr("No memory for anchor\n");
- }
- else if (file = Open(pathname, MODE_OLDFILE) ) /* Just one file ? */
- {
- Close(file);
- return ShowPicture(pathname);
- }
- else /* No wildcards, and not a file: it's a device or a directory */
- {
- strcpy(buf, pathname);
- AddPart(pathname=buf, "#?", sizeof(buf));
- goto iswild; /* Not really elegant, but it works */
- }
-
- return cont;
- }
-
-
- /****************************************************************************
- ** Started without arguments: create or delete our appicon
- */
-
- void AppIconStuff(void)
- {
- struct MsgPort *msgport;
- struct AppIcon *ai;
- struct AppMessage *amsg;
-
- if (msgport = FindPort(APPICONPORTNAME) ) /* Already running ? */
- {
- Signal(msgport->mp_SigTask, SIGBREAKF_CTRL_C); /* Yes ---> Kill it */
- }
- else if(msgport = CreateMsgPort() )
- {
- struct DiskObject *appdobj = NULL;
- char *tooltype;
-
- msgport->mp_Node.ln_Name = APPICONPORTNAME;
- AddPort(msgport);
-
- /*
- ** If an "ICON" tooltype is specified, we use this as the
- ** appicon for ShowIFF. Default is ShowIFF's own icon image.
- */
- if (tooltype = FindToolType(dobj->do_ToolTypes, ICONTOOLTYPE) )
- appdobj = GetDiskObject(tooltype);
-
- if (appdobj == NULL) appdobj = dobj;
-
- /*
- ** Position of the appicon can be specified with "ICON[XY]POS"
- */
- if (tooltype = FindToolType(dobj->do_ToolTypes, XPOSTOOLTYPE) )
- appdobj->do_CurrentX = GetNumber(tooltype);
- else
- appdobj->do_CurrentX = NO_ICON_POSITION;
-
- if (tooltype = FindToolType(dobj->do_ToolTypes, YPOSTOOLTYPE) )
- appdobj->do_CurrentY = GetNumber(tooltype);
- else
- appdobj->do_CurrentY = NO_ICON_POSITION;
-
- /*
- ** The appicon's name is set with "ICONNAME"
- */
- if ( !(tooltype = FindToolType(dobj->do_ToolTypes, ICONNAMETOOLTYPE)) )
- tooltype = DEFAULTAPPICONNAME;
-
- /*
- ** Add our appicon
- */
- if (ai = AddAppIconA(0, 0, tooltype, msgport, NULL, appdobj, NULL) )
- {
- while ( !(Wait(1L << msgport->mp_SigBit | SIGBREAKF_CTRL_C)
- & SIGBREAKF_CTRL_C) )
- {
- if (wbwindow = Open(WindowTitle, MODE_OLDFILE) )
- {
- oldcos = SelectOutput(wbwindow);
- }
-
- while(amsg = (struct AppMessage *)GetMsg(msgport) )
- {
- struct WBArg *arg = amsg->am_ArgList;
- int i, cont = TRUE;
-
- for(i=0; (i < amsg->am_NumArgs) && cont; i++,arg++)
- {
- BPTR oldcd = 0;
- if(arg->wa_Lock) oldcd = CurrentDir(arg->wa_Lock);
- else DisplayBeep(NULL);
-
- cont = ShowPattern(arg->wa_Name && *arg->wa_Name
- ? (STRPTR)arg->wa_Name : "#?");
- if(oldcd) CurrentDir(oldcd);
- }
- ReplyMsg(amsg);
- }
-
- ClosePicture(&pic2); /* Close last screen */
-
-
- if(wbwindow)
- {
- WaitForChar(wbwindow, 2L<<20); /* Wait 2 seconds */
- SelectOutput(oldcos);
- oldcos = 0;
- Close(wbwindow);
- wbwindow = NULL;
- SetSignal(0, SIGBREAKF_CTRL_C); /* Clear break sig */
- }
- }
- RemoveAppIcon(ai);
- }
-
- if(appdobj != dobj) FreeDiskObject(appdobj);
-
- /*
- ** Make sure there are no more messages pending
- */
- while (amsg = (struct AppMessage *)GetMsg(msgport) )
- ReplyMsg(amsg);
-
- RemPort(msgport);
- DeleteMsgPort(msgport);
- }
- }
-
-
- /****************************************************************************
- ** The entry point, called from ArgsStartup20.o
- */
-
- LONG Main(struct WBStartup *startup, LONG arglen)
- {
- #define argline ((char *)startup)
-
- /*
- ** Open all needed libraries
- */
- if ( !(UtilityBase = OpenLibrary(UTILITYNAME, 36L)) )
- goto quit;
-
- if ( !(GfxBase = (struct GfxBase *)OpenLibrary(GRAPHICSNAME, 36L)) )
- goto quit;
-
- if ( !(IntuitionBase = (void *)OpenLibrary("intuition.library", 36L)) )
- goto quit;
-
- if ( !(IconBase = OpenLibrary(ICONNAME, 36L)) )
- goto quit;
-
- if ( !(WorkbenchBase = OpenLibrary(WORKBENCH_NAME, 36L)) )
- goto quit;
-
- if ( !(IFFBase = OpenLibrary(IFFNAME, 19L)) )
- goto quit;
-
- if (IFFBase->lib_Version < IFFVERSION)
- PutStr("WARNING: you have an old version of iff.library\n");
-
-
- /*
- ** Get args from WB or CLI as appropriate
- */
- if (arglen) /* From CLI */
- {
- if (*argline != '\n')
- {
- if (argv.DelayPtr)
- delay = *argv.DelayPtr * SysBase->VBlankFrequency + 1;
-
- if (argv.Monitor)
- monitorid = GetNumber(argv.Monitor);
-
- do
- {
- char **pattern = argv.Patterns;
-
- if (*pattern)
- {
- while (*pattern)
- if (!ShowPattern(*pattern++) )
- goto done;
- }
- else ShowPattern("#?");
-
- } while (argv.LoopFlag);
- done:
- PutStr("All done.\n");
- }
- else
- {
- PutStr(VersionString+7);
- PutStr(CLI_Help);
- }
- }
- else /* Called from Workbench */
- {
- /*
- ** Set defaults for Workbench
- */
- argv.AllFlag = TRUE;
- // argv.LoopFlag = FALSE;
- // argv.NoBreakFlag = FALSE;
- // argv.NoOverscanFlag = FALSE;
-
- if (dobj = GetDiskObject(startup->sm_ArgList->wa_Name))
- {
- char *tooltype;
-
- #if 0
- if (tooltype = FindToolType(dobj->do_ToolTypes, OPTIONSTOOLTYPE) )
- {
- GADS(tooltype, strlen(tooltype), NULL, argv, CLI_Template);
- if (argv.DelayPtr)
- delay = *argv.DelayPtr * SysBase->VBlankFrequency + 1;
- }
- #endif
-
- if (tooltype = FindToolType(dobj->do_ToolTypes, "MONITOR") )
- monitorid = GetNumber(tooltype);
- }
-
- if (startup->sm_NumArgs > 1) /* Started with some arguments */
- {
- struct WBArg *arg = startup->sm_ArgList;
- int i;
-
- /*
- ** Open our output window
- */
- if (wbwindow = Open(WindowTitle, MODE_OLDFILE) )
- oldcos = SelectOutput(wbwindow);
-
- for (i=1; i<startup->sm_NumArgs; ++i)
- {
- arg++;
- if (arg->wa_Lock) CurrentDir(arg->wa_Lock);
- else PutStr("Can't lock directory\n");
-
- if (arg->wa_Name && *arg->wa_Name)
- {
- if (!ShowPattern(arg->wa_Name) )
- break;
- }
- else ShowPattern("#?");
- }
-
- PutStr("All done.\n");
- }
- else /* no arguments, just clicked */
- {
- AppIconStuff();
- }
- }
-
-
- /*
- ** Cleanup
- */
- quit:
- ClosePicture(&pic1);
- ClosePicture(&pic2);
-
- if(ifffile) IFFL_CloseIFF(ifffile);
-
- if (dobj)
- {
- FreeDiskObject(dobj);
- // dobj = NULL;
- }
-
- if(wbwindow)
- {
- WaitForChar(wbwindow, 3L<<20); /* Wait 3 seconds */
- Close(wbwindow);
- // wbwindow = 0;
- }
-
- if (oldcos)
- {
- SelectOutput(oldcos);
- // oldcos = 0;
- }
-
- CloseLibrary(IFFBase);
- CloseLibrary(WorkbenchBase);
- CloseLibrary(IconBase);
- CloseLibrary(IntuitionBase);
- CloseLibrary(GfxBase);
- CloseLibrary(UtilityBase);
-
- return RETURN_OK;
- }
-